package com.wodsy.phoenix.dataservice.shopc.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.wodsy.phoenix.datadao.shopc.dao.FreightTempAreaDao;
import com.wodsy.phoenix.datadao.shopc.dao.FreightTempDao;
import com.wodsy.phoenix.datadao.shopc.dao.FreightTempDeliveryMethodDao;
import com.wodsy.phoenix.datadao.shopc.dao.FreightTempPriceUnitDao;
import com.wodsy.phoenix.dataobject.base.Pager;
import com.wodsy.phoenix.dataobject.base.PhoenixGenericResponse;
import com.wodsy.phoenix.dataobject.base.PhoenixResponseWrapper;
import com.wodsy.phoenix.dataobject.base.ResponseCodeConstants;
import com.wodsy.phoenix.dataobject.shopc.model.*;
import com.wodsy.phoenix.dataobject.shopc.vo.CalculateFreight;
import com.wodsy.phoenix.dataservice.shopc.service.FreightTempService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * Created by Huang on 2015/4/15.
 */
@Service(interfaceName="com.wodsy.phoenix.dataservice.shopc.service.FreightTempService" ,timeout = 1000000)
public class FreightTempServiceImpl implements FreightTempService {

    protected Logger logger = Logger.getLogger(this.getClass());

    @Autowired
    private FreightTempDao freightTempDao;
    @Autowired
    private FreightTempPriceUnitDao priceUnitDao;
    @Autowired
    private FreightTempDeliveryMethodDao deliveryMethodDao;
    @Autowired
    private FreightTempAreaDao freightTempAreaDao;

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<CalculateFreight> calculateFreight(CalculateFreight calculateFreight) {
        try {
            calculateFreightInternal(calculateFreight);
            return new PhoenixResponseWrapper<CalculateFreight>(calculateFreight);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            return new PhoenixResponseWrapper<CalculateFreight>(ResponseCodeConstants.EXCEPTION,e.getMessage());
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<CalculateFreight> calculateFreight(List<CalculateFreight> calculateFreights) {
        try {
            for (CalculateFreight calculateFreight : calculateFreights) {
                calculateFreightInternal(calculateFreight);
            }
            return new PhoenixResponseWrapper<CalculateFreight>(calculateFreights);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            return new PhoenixResponseWrapper<CalculateFreight>(ResponseCodeConstants.EXCEPTION,e.getMessage());
        }
    }

    @Override
    @Transactional(value="xa",rollbackFor=Exception.class)
    public PhoenixResponseWrapper<PhoenixGenericResponse> addFreightTemp(FreightTemp freightTemp) {
        try {
            freightTemp.setAddTime(new Date());
            freightTemp.setUpdateTime(new Date());
            freightTempDao.save(freightTemp);
            return new PhoenixResponseWrapper<PhoenixGenericResponse>(new PhoenixGenericResponse(freightTemp.getId()));
        } catch (Exception e) {
            logger.error("",e);
            return new PhoenixResponseWrapper<PhoenixGenericResponse>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",rollbackFor=Exception.class)
    public PhoenixResponseWrapper<PhoenixGenericResponse> mergeFreightTemp(FreightTemp freightTemp) {
        try {
            FreightTemp old = freightTempDao.get(freightTemp.getId());
            old.setUpdateTime(new Date());
            old.setName(freightTemp.getName());
            old.setIsFree(freightTemp.getIsFree());

            //sub
            old.addFreightTempSubs(freightTemp.getFreightTempSubs());

            freightTempDao.update(freightTemp);
            return new PhoenixResponseWrapper<PhoenixGenericResponse>(new PhoenixGenericResponse(freightTemp.getId()));
        } catch (Exception e) {
            logger.error("",e);
            return new PhoenixResponseWrapper<PhoenixGenericResponse>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",rollbackFor=Exception.class)
    public PhoenixResponseWrapper<PhoenixGenericResponse> delFreightTemp(int id) {
        try {
            FreightTemp temp = freightTempDao.get(id);
            freightTempDao.delete(temp);
            return new PhoenixResponseWrapper<PhoenixGenericResponse>();
        } catch (Exception e) {
            logger.error("",e);
            return new PhoenixResponseWrapper<PhoenixGenericResponse>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTemp> getFreightTemp(int id) {
        try {
            FreightTemp freightTemp = freightTempDao.get(id);
            if (freightTemp != null){
                return new PhoenixResponseWrapper<FreightTemp>(freightTemp);
            }else {
                return new PhoenixResponseWrapper<FreightTemp>(ResponseCodeConstants.EMPTY,"empty result");
            }
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTemp>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTemp> findFreightTempsByOwnerInfo(Pager<FreightTemp> pager,int shopId, int userId) {
        try {
            Pager<FreightTemp> pager1 = freightTempDao.findFreightTempsByOwnerInfo(pager, shopId, userId);
            return new PhoenixResponseWrapper<FreightTemp>(pager1);
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTemp>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTemp> findFreightTempsByOwnerInfo(int shopId, int userId) {
        try {
            List<FreightTemp> list = freightTempDao.findFreightTempsByOwnerInfo(shopId,userId);
            return new PhoenixResponseWrapper<FreightTemp>(list);
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTemp>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTempPriceUnit> findFreightTempPriceUnit() {
        try {
            Pager<FreightTempPriceUnit> pager = new Pager<FreightTempPriceUnit>();
            List<FreightTempPriceUnit> list = priceUnitDao.findByAll();
            if (list != null && !list.isEmpty()){
                pager.setItems(list);
                pager.setTotalCount(list.size());
                return new PhoenixResponseWrapper<FreightTempPriceUnit>(pager);
            }else{
                return new PhoenixResponseWrapper<FreightTempPriceUnit>(ResponseCodeConstants.EMPTY, "empty result");
            }
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTempPriceUnit>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTempPriceUnit> getFreightTempPriceUnit(int id) {
        try {
            FreightTempPriceUnit priceUnit = priceUnitDao.get(id);
            if (priceUnit != null){
                return new PhoenixResponseWrapper<FreightTempPriceUnit>(priceUnit);
            }else {
                return new PhoenixResponseWrapper<FreightTempPriceUnit>(ResponseCodeConstants.EMPTY,"empty result");
            }
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTempPriceUnit>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTempDeliveryMethod> findFreightTempDeliveryMethod() {
        try {
            Pager<FreightTempDeliveryMethod> pager = new Pager<FreightTempDeliveryMethod>();
            List<FreightTempDeliveryMethod> list = deliveryMethodDao.findByAll();
            if (list != null && !list.isEmpty()){
                pager.setItems(list);
                pager.setTotalCount(list.size());
                return new PhoenixResponseWrapper<FreightTempDeliveryMethod>(pager);
            }else{
                return new PhoenixResponseWrapper<FreightTempDeliveryMethod>(ResponseCodeConstants.EMPTY, "empty result");
            }
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTempDeliveryMethod>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    @Override
    @Transactional(value="xa",readOnly=true)
    public PhoenixResponseWrapper<FreightTempDeliveryMethod> getFreightTempDeliveryMethod(int id) {
        try {
            FreightTempDeliveryMethod deliveryMethod = deliveryMethodDao.get(id);
            if (deliveryMethod != null){
                return new PhoenixResponseWrapper<FreightTempDeliveryMethod>(deliveryMethod);
            }else {
                return new PhoenixResponseWrapper<FreightTempDeliveryMethod>(ResponseCodeConstants.EMPTY,"empty result");
            }
        } catch (Exception e) {
            logger.error("", e);
            return new PhoenixResponseWrapper<FreightTempDeliveryMethod>(ResponseCodeConstants.EXCEPTION,"exception occur");
        }
    }

    private CalculateFreight calculateFreightInternal(CalculateFreight calculateFreight) {
        // 如果是免运费的，直接返回结果
        // 如果是非免运费的
            // 判断运费计价方式分别计算 计算单价通过地区判断
        int ftId = calculateFreight.getFtId();
        int deliveryMethodId = calculateFreight.getDeliveryMethodId();
        int areaId = calculateFreight.getAreaId();
        FreightTemp temp = freightTempDao.get(ftId);
        if(temp != null){
            if(temp.getIsFree()){
                calculateFreight.setFreight(0);
            }else{
                int inRange = 0;
                int inRangePrice = 0;
                int outRange = 0;
                int outRangePrice = 0;
                boolean findArea = false;
                Set<FreightTempSub> freightTempSubs = temp.getFreightTempSubs();
                for (FreightTempSub freightTempSub : freightTempSubs) {
                    if (freightTempSub.getDeliveryMethod().getId() == deliveryMethodId){
                        Set<FreightTempDestination> destinations = freightTempSub.getDestinations();
                        if (destinations != null && !destinations.isEmpty()){
                            for (FreightTempDestination destination : destinations){
                                Set<FreightTempArea> areas = destination.getAreas();
                                if(areas != null && !areas.isEmpty()){
                                    for(FreightTempArea area : areas){
                                        if (areaId == area.getAreaId()){
                                            findArea = true;
                                            break;
                                        }
                                    }
                                }
                                if (findArea){
                                    inRange = destination.getInRange();
                                    inRangePrice = destination.getInRangePrice();
                                    outRange = destination.getOutRangeWeight();
                                    outRangePrice = destination.getOutRangePrice();
                                    break;
                                }
                            }
                        }
                        if (!findArea){
                            inRange = freightTempSub.getInRange();
                            inRangePrice = freightTempSub.getInRangePrice();
                            outRange = freightTempSub.getOutRangeWeight();
                            outRangePrice = freightTempSub.getOutRangePrice();
                            break;
                        }
                    }
                }

                FreightTempPriceUnit priceUnit = temp.getPriceUnit();
                int freight = 0;
                switch (priceUnit.getId()){
                    case 1:
                        // 按件数
                        int count = calculateFreight.getCount();
                        if (count <= inRange){
                            freight = inRangePrice;
                        }else {
                            freight = inRangePrice;
                            int over = count - inRange;
                            freight += ((over/outRange) + (over%outRange==0?0:1)) * outRangePrice;
                        }
                        calculateFreight.setFreight(freight);
                        break;
                    case 2:
                        // 按重量
                        int weight = calculateFreight.getWeight();
                        if (weight <= inRange){
                            freight = inRangePrice;
                        }else {
                            freight = inRangePrice;
                            int over = weight - inRange;
                            freight += ((over/outRange) + (over%outRange==0?0:1)) * outRangePrice;
                        }
                        calculateFreight.setFreight(freight);
                        break;
                    case 3:
                        // 按体积
                        int volume = calculateFreight.getVolume();
                        if (volume <= inRange){
                            freight = inRangePrice;
                        }else {
                            freight = inRangePrice;
                            int over = volume - inRange;
                            freight += ((over/outRange) + (over%outRange==0?0:1)) * outRangePrice;
                        }
                        calculateFreight.setFreight(freight);
                        break;
                    default:
                        break;
                }

            }
        }else{
            throw new RuntimeException("没有查到运费模板，无法计算");
        }
        return calculateFreight;
    }

    public Logger getLogger() {
        return logger;
    }

    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    public FreightTempDao getFreightTempDao() {
        return freightTempDao;
    }

    public void setFreightTempDao(FreightTempDao freightTempDao) {
        this.freightTempDao = freightTempDao;
    }

    public FreightTempPriceUnitDao getPriceUnitDao() {
        return priceUnitDao;
    }

    public void setPriceUnitDao(FreightTempPriceUnitDao priceUnitDao) {
        this.priceUnitDao = priceUnitDao;
    }

    public static void main(String[] args) {
        com.alibaba.dubbo.container.Main.main(args);
    }
}
